# Map width and height constants
$map_width = 45
$map_height = 18

# All things in the game
$floor1     = Thing.new('Cave floor',    '.', 6)
$floor2     = Thing.new('Stone floor',   '.', 0)
$floor3     = Thing.new('Wood floor',    '.', 3)
$wall1      = Thing.new('Cave wall',     '#', 6)
$wall2      = Thing.new('Stone wall',    '#', 0)
$wall3      = Thing.new('Wood wall',     '#', 3)
$spike      = Thing.new('Stalagmite',    '^', 6)
$tree       = Thing.new('Mushroom tree', 'Y', 3)
$water      = Thing.new('Water',         '~', 4)
$blood      = Thing.new('Blood',         '.', 1)
$door       = Thing.new('Door',          '+', 3)
$opendoor   = Thing.new('Open door',     '.', 3)

class Map
  def initialize(x, y)
    @x, @y = x, y
    # Map array
    @map = Array.new($map_height) {
      Array.new($map_width) { $floor1 }
    }
    # Ensure data folder exists
    if !File.exists?("data/")
      Dir.mkdir("data")
    end
    # Load map if map exists
    if File.exist?("data/#{x}-#{y}.dat")
      self.readfile
    # Generate map if map doesn't exist
    else
      self.generate
    end
    self.save
  end
  def addspikes(count)
    for i in 1..count
      rx = rand($map_width)
      ry = rand($map_height)
      self.rect(rx - 1, ry - 1, rx + 1, ry + 1, $floor1)
      self.addthing(rx, ry, $spike)
    end
  end
  def addtrees(count)
    for i in 1..count
      rx = rand($map_width)
      ry = rand($map_height)
      self.rect(rx - 1, ry - 1, rx + 1, ry + 1, $floor1)
      self.addthing(rx, ry, $tree)
    end
  end
  def rect(startx, starty, endx, endy, thing)
    @map.drop($map_height - endy).each_with_index do |row, y|
      next if y < starty
      row.drop($map_width - endx).each_with_index do |cell, x|
        next if x < startx
        self.addthing(x, y, thing)
      end
    end
  end
  def frectv(startx, starty, endx, endy, thing)
    # vertical fuzz
    @map.drop($map_height - endy).each_with_index do |row, y|
      next if y < starty
      row.drop($map_width - endx).each_with_index do |cell, x|
        next if x < startx
        self.addthing(x, y - rand(2), thing)
        self.addthing(x, y + rand(2), thing)
        self.addthing(x, y, thing)
      end
    end
  end
  def frecth(startx, starty, endx, endy, thing)
    # horizontal fuzz
    @map.drop($map_height - endy).each_with_index do |row, y|
      next if y < starty
      row.drop($map_width - endx + rand(2) ).each_with_index do |cell, x|
        next if x < startx - rand(2)
        self.addthing(x, y, thing)
      end
    end
  end
  def room1(startx, starty, width, height)
    self.rect(startx, starty, startx + width, starty + height, $floor2)
    self.rect(startx, starty, startx + width, starty + 1, $wall2)                   # top
    self.rect(startx, starty + height - 1, startx + width, starty + height, $wall2) # bottom
    self.rect(startx, starty, startx + 1, starty + height, $wall2)                  # left
    self.rect(startx + width - 1, starty, startx + width, starty + height, $wall2)  # right
    self.rect(startx + 4, starty + height - 1, startx + 5, starty + height, $door) # door
  end
  def room2(startx, starty, width, height)
    self.rect(startx, starty, startx + width, starty + height, $floor2)
    self.rect(startx, starty, startx + width, starty + 1, $wall2)                   # top
    self.rect(startx, starty + height - 1, startx + width, starty + height, $wall2) # bottom
    self.rect(startx, starty, startx + 1, starty + height, $wall2)                  # left
    self.rect(startx + width - 1, starty, startx + width, starty + height, $wall2)  # right
    self.rect(startx + width - 5, starty, startx + width - 4, starty + 1, $door) # door
  end
  def fort(startx, starty, width, height)
    self.rect(startx, starty, startx + width, starty + 1, $wall2)                   # top
    self.rect(startx, starty + height - 1, (startx + width / 2) - 3, starty + height, $wall2) # bottom_left
    self.rect( (startx + width / 2) + 3, starty + height - 1, startx + width, starty + height, $wall2) #bottom right
    self.rect(startx, starty, startx + 1, starty + height, $wall2)                  # left
    self.rect(startx + width - 1, starty, startx + width, starty + height, $wall2)  # right
  end
  def getx
    return @x
  end
  def gety
    return @y
  end
  def getchar(x, y)
    return @map[y][x].getchar
  end
  def getname(x, y)
    return @map[y][x].getname
  end
  def gettype
    return @type
  end
  def addthing(x, y, thing)
    @map[y][x] = thing
  end
  def draw
    @map.each_with_index do |row, y|
      row.each_with_index do |cell, x|
        setpos y, x
        if cell.getcolor > 6
          attron(A_BOLD)
        end
        attron(color_pair(cell.getcolor))
        addch cell.getchar
        attroff(color_pair(cell.getcolor))
        attroff(A_BOLD)
      end
    end
  end
  def readfile
    @map = YAML::load File.read("data/#{@x}-#{@y}.dat")
  end
  def loadmap(x, y)
    newmap = Map.new(x, y)
    $currentmap = newmap
  end
  def save
    mapfilename = "#{@x}-#{@y}"
    mapdata = YAML::dump(@map)
    File.open("data/#{mapfilename}.dat", 'w') do |f|
      f.write(mapdata)
    end
  end
  def generate
    # Create map based on type
    @type = $world[@y][@x]
    case @type
      when $MAP_LAND        # 0
        self.addspikes(20)
        self.addtrees(10)
      when $MAP_CLIFF_W     # 1
        self.addspikes(20)
        self.addtrees(10)
        self.frecth(0, 0, $map_width / 2, $map_height, $wall1)
        self.rect(0, 0, 1, $map_height, $wall1)
      when $MAP_CLIFF_E     # 2
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width  / 2 , 0, $map_width, $map_height, $wall1)
        self.rect($map_width - 1, 0, $map_width, $map_height, $wall1)
      when $MAP_CLIFF_S     # 3
        self.addspikes(20)
        self.addtrees(10)
        self.frectv(0, $map_height / 2, $map_width, $map_height - 1, $wall1)
        self.rect(0, $map_height - 1, $map_width, $map_height, $wall1)
      when $MAP_CLIFF_N     # 4
        self.addspikes(20)
        self.addtrees(10)
        self.frectv(0, 0, $map_width, $map_height / 2, $wall1)
        self.rect(0, $map_height - 1, $map_width, $map_height, $floor1)
      when $MAP_CLIFF_NW_OUT # 5
        self.addspikes(20)
        self.addtrees(10)
        self.frecth(0,0,$map_width / 2 + 1, $map_height / 2, $wall1)
        self.frectv(0,0,$map_width / 2, $map_height / 2, $wall1)
        self.rect(0, $map_height - 1, $map_width / 2, $map_height, $floor1)
      when $MAP_CLIFF_NE_OUT # 6
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2, 0, $map_width, $map_height / 2, $wall1)
        self.frectv($map_width / 2, 0, $map_width, $map_height / 2, $wall1)
        self.rect($map_width / 2, $map_height - 1, $map_width, $map_height, $floor1)
      when $MAP_CLIFF_SW_OUT # 7
        self.addspikes(20)
        self.addtrees(10)
        self.frectv(0,$map_height / 2, $map_width / 2, $map_height / 2 + 2, $wall1)
        self.frecth(0,$map_height / 2 + 2, $map_width / 2, $map_height, $wall1)
      when $MAP_CLIFF_SE_OUT # 8
        self.addspikes(20)
        self.addtrees(10)
        self.frectv($map_width / 2, $map_height / 2 , $map_width, $map_height / 2 + 2, $wall1)
        self.frecth($map_width / 2, $map_height / 2 + 2 , $map_width, $map_height, $wall1)
        self.rect($map_width - 1, $map_height / 2, $map_width, $map_height, $wall1)
      when $MAP_CLIFF_NW_IN # 9
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2, 0, $map_width, $map_height, $wall1)
        self.frectv(0, $map_height / 2, $map_width, $map_height, $wall1)
      when $MAP_CLIFF_NE_IN # 10
        self.addspikes(20)
        self.addtrees(10)
        self.frecth(0, 0, $map_width / 2, $map_height / 2, $wall1)
        self.frectv(0, $map_height / 2, $map_width, $map_height - 1, $wall1)
        self.rect(0, $map_height - 1, $map_width, $map_height, $wall1)
      when $MAP_CLIFF_SW_IN # 11
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2, 0, $map_width, $map_height, $wall1)
        self.frectv(0, 0, $map_width, $map_height / 2, $wall1)
      when $MAP_CLIFF_SE_IN # 12
        self.addspikes(20)
        self.addtrees(10)
        self.frecth(0, 0, $map_width / 2, $map_height, $wall1)
        self.frectv(0, 0, $map_width, $map_height / 2, $wall1)
      when $MAP_LAND_RIVER # 13
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2 - 3, 0, $map_width / 2 + 3, $map_height, $water)
      when $MAP_LAND_BRIDGE # 14
        self.addspikes(20)
        self.addtrees(10)
        self.frectv(0, $map_height / 2, $map_width, $map_height / 2 + 1, $floor3)
        self.frecth($map_width / 2 - 3, 0, $map_width / 2 + 3, $map_height, $water)
        self.rect($map_width / 2 - 5, $map_height / 2 - 1, $map_width / 2 + 4, $map_height / 2 + 2, $floor2)
      when $MAP_LAND_FORT  # 15
        self.addspikes(20)
        self.addtrees(10)
        self.frectv(4, $map_height / 2, $map_width - 4, $map_height / 2 + 1, $floor3)
        self.frecth($map_width / 2 - 1, 3, $map_width / 2 + 2, $map_height, $floor3)
        self.fort(2,1, $map_width - 4, $map_height - 2)
        self.room1(5, 3, 12, 5)
        self.room2(6, 10, 11, 5)
        self.room1($map_width / 2 + 5, 3, 12, 5)
        self.room2($map_width / 2 + 6, 10, 11, 5)
      when $MAP_CLIFF  # 16
        self.rect(0, 0, $map_width, $map_height, $wall1)
      when $MAP_SEA # 17
        self.rect(0, 0, $map_width, $map_height, $water)
      when $MAP_SEA_W     # 18
        self.addspikes(12)
        self.addtrees(6)
        self.frecth(0, 0, $map_width / 2, $map_height, $water)
        self.rect(0, 0, 1, $map_height, $water)
      when $MAP_SEA_E     # 19
        self.addspikes(12)
        self.addtrees(6)
        self.frecth($map_width  / 2 , 0, $map_width, $map_height, $water)
        self.rect($map_width - 1, 0, $map_width, $map_height, $water)
      when $MAP_SEA_S     # 20
        self.addspikes(12)
        self.addtrees(6)
        self.frectv(0, 0, $map_width, $map_height / 2, $water)
        self.rect(0, $map_height - 1, $map_width, $map_height, $floor1)
      when $MAP_SEA_N     # 21
        self.addspikes(12)
        self.addtrees(6)
        self.frectv(0, $map_height / 2, $map_width, $map_height - 1, $water)
        self.rect(0, $map_height - 1, $map_width, $map_height, $water)
      when $MAP_SEA_NW_OUT # 22
        self.addspikes(12)
        self.addtrees(6)
        self.frectv(0,0,$map_width / 2, $map_height / 2, $water)
        self.frecth(0,0,$map_width / 2 + 1, $map_height / 2, $water)
        self.rect(0, $map_height - 1, $map_width, $map_height, $floor1)
      when $MAP_SEA_NE_OUT # 23
        self.addspikes(12)
        self.addtrees(6)
        self.frectv($map_width / 2, 0, $map_width, $map_height / 2, $water)
        self.frecth($map_width / 2, 0, $map_width, $map_height / 2, $water)
        self.rect(0, $map_height - 1, $map_width, $map_height, $floor1)
      when $MAP_SEA_SW_OUT # 24
        self.addspikes(12)
        self.addtrees(6)
        self.frectv(0, $map_height / 2, $map_width / 2, $map_height / 2 + 2, $water)
        self.frecth(0, $map_height / 2 + 2, $map_width / 2, $map_height, $water)
      when $MAP_SEA_SE_OUT # 25
        self.addspikes(12)
        self.addtrees(6)
        self.frectv($map_width / 2, $map_height / 2, $map_width, $map_height / 2 + 1, $water)
        self.frecth($map_width / 2, $map_height / 2 + 1, $map_width, $map_height, $water)
        self.rect($map_width - 1, $map_height / 2, $map_width, $map_height, $water)
      when $MAP_SEA_NW_IN # 26
        self.addspikes(12)
        self.addtrees(10)
        self.frecth($map_width / 2, 0, $map_width, $map_height / 2, $water)
        self.frectv(0, $map_height / 2, $map_width, $map_height - 1, $water)
        self.rect(0, $map_height - 1, $map_width, $map_height, $water)
        self.rect($map_width - 1, 0, $map_width, $map_height, $water)
      when $MAP_SEA_NE_IN # 27
        self.addspikes(12)
        self.addtrees(6)
        self.frecth(0, 0, $map_width / 2 + 1, $map_height, $water)
        self.frectv($map_width / 2, $map_height / 2, $map_width, $map_height - 1, $water)
        self.rect(0, $map_height - 1, $map_width, $map_height, $water)
      when $MAP_SEA_SW_IN # 28
        self.addspikes(12)
        self.addtrees(6)
        self.frectv(0, 0, $map_width, $map_height / 2, $water)
        self.frecth($map_width / 2, 0, $map_width, $map_height, $water)
        self.rect($map_width - 1, 0, $map_width, $map_height, $water)
        self.rect(0, $map_height - 1, $map_width / 2, $map_height, $floor1)
        self.rect($map_width / 2, $map_height - 1, $map_width, $map_height, $water)
      when $MAP_SEA_SE_IN # 29
        self.addspikes(12)
        self.addtrees(6)
        self.frectv(0, 0, $map_width, $map_height / 2, $water)
        self.frecth(0, $map_height / 2, $map_width / 2, $map_height, $water)
        self.rect($map_width / 2, $map_height - 1, $map_width, $map_height, $floor1)
      when $MAP_SEA_RIVER # 30
        self.addspikes(12)
        self.addtrees(6)
        self.frectv(0, 0, $map_width, $map_height / 2, $water)
        self.rect(0, $map_height - 1, $map_width, $map_height, $floor1)
        self.frecth($map_width / 2 - 3, $map_height / 2, $map_width / 2 + 3, $map_height, $water)
      when $MAP_SEA_PORT # 31
        self.addspikes(12)
        self.addtrees(6)
        self.frectv(0, 0, $map_width, $map_height / 2, $water)
        self.rect($map_width / 2 - 1, $map_height / 2 - 5, $map_width /2 + 1, $map_height / 2 + 1, $floor3)
        self.rect(0, $map_height - 1, $map_width, $map_height, $floor1)
      when $MAP_RIVER_CLIFF # 32
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2 - 3, 0, $map_width / 2 + 3, $map_height, $water)
        self.frectv(0, $map_height / 2, $map_width, $map_height - 1, $wall1)
        self.rect(0, $map_height - 1, $map_width, $map_height, $wall1)
      when $MAP_LAND_ROAD_NS # 33
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2 - 1, 0, $map_width / 2 + 2, $map_height, $floor3)
      when $MAP_LAND_ROAD_EW # 34
        self.addspikes(20)
        self.addtrees(10)
        self.frectv(0, $map_height / 2, $map_width, $map_height / 2 + 1, $floor3)
      when $MAP_LAND_ROAD_NE # 35
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2 - 1, $map_height / 2, $map_width / 2 + 2, $map_height, $floor3)
        self.frectv($map_width / 2, $map_height / 2, $map_width, $map_height / 2 + 1, $floor3)
      when $MAP_LAND_ROAD_NW # 36
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2 - 1, $map_height / 2, $map_width / 2 + 2, $map_height, $floor3)
        self.frectv(0, $map_height / 2, $map_width / 2, $map_height / 2 + 1, $floor3)
      when $MAP_LAND_ROAD_SE # 37
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2 - 1, 0, $map_width / 2 + 2, $map_height / 2, $floor3)
        self.frectv($map_width / 2, $map_height / 2, $map_width, $map_height / 2 + 1, $floor3)
      when $MAP_LAND_ROAD_SW # 38
        self.addspikes(20)
        self.addtrees(10)
        self.frecth($map_width / 2 - 1, 0, $map_width / 2 + 2, $map_height / 2, $floor3)
        self.frectv(0, $map_height / 2, $map_width / 2, $map_height / 2 + 1, $floor3)
      else
        # do nothing
    end
  end
end